package cn.ljy.quicksnip.utils.plc;

import com.github.s7connector.api.DaveArea;
import com.github.s7connector.api.S7Connector;
import com.github.s7connector.api.factory.S7ConnectorFactory;

import java.nio.ByteBuffer;
import java.util.concurrent.TimeUnit;

public class PLCUtil {

    private S7Connector s7Connector;
    /**
     * 初始化PLC连接
     *
     * @param ipAddress PLC的IP地址
     * @param port PLC的TCP端口
     * @param rack 机架号
     * @param slot 插槽号
     * @return 初始化后的S7Connector实例
     */
    public S7Connector initConnect(String ipAddress, int port, int rack, int slot) {
        // 创建S7Connector实例
        s7Connector = S7ConnectorFactory.buildTCPConnector()
                .withHost(ipAddress)
                .withPort(port)
                .withRack(rack)
                .withSlot(slot)
                .withTimeout(10000) // 连接超时时间（毫秒）
                .build();

        // 可选：创建S7Serializer实例
//        S7Serializer serializer = S7SerializerFactory.buildSerializer(connector);
        return s7Connector;
    }

    /**
     * 写入PLC元件
     * 说明：
     * DaveArea是s7connector库中用于指定PLC内存区域的枚举类型。它定义了不同的内存区域，如DB块、输入区、输出区等。在与PLC进行数据交互时，需要指定要操作的内存区域，DaveArea提供了这些区域的标识。
     * DaveArea的定义
     * DaveArea枚举类型定义了以下几种常见的PLC内存区域：
     * DB：数据块（Data Block）
     * PE：输入区（Process Image Input）
     * PA：输出区（Process Image Output）
     * MK：中间区（Memory Area）
     * CT：计数器区（Counter Area）
     * TM：定时器区（Timer Area）
     * @param daveArea 内存区域
     * @param dbNumber 数据块编号
     * @param startOffset 数据偏移量
     * @param words
     */
    public void write(DaveArea daveArea,int dbNumber,int startOffset,byte[] words){
        //使用allocate方法分配的内存是在Java虚拟机的堆内存中,allocate(4)表示创建一个容量为4字节
        //put写入一个字节数据
//        int writeValue = 12345;
//        byte[] writeBuffer = ByteBuffer.allocate(4).putInt(writeValue).array();
        s7Connector.write(daveArea, dbNumber, startOffset, words);
        System.out.println("数据已经发送到PLC");
    }

    /**
     * 读取数据
     * @param area
     * @param dbNumber
     * @param startAddress
     * @param length
     * @return
     */
    public byte[] readData(DaveArea area, int dbNumber, int startAddress, int length) {
        return s7Connector.read(area, dbNumber, length,startAddress);
    }

    /**
     * 读取数据
     * @param area
     * @param dbNumber
     * @param startAddress
     * @param length
     * @param pollingMillseconds 轮训的等待时间
     * @return
     */
    public String readAndWaiteForData(DaveArea area, int dbNumber, int startAddress, int length,int pollingMillseconds) throws InterruptedException {
        String responseValue=null;
        boolean responseReceived = false;
        while (!responseReceived) {
            // 读取PLC中响应数据的状态
            byte[] readBuffer =readData(area, dbNumber, startAddress, length);
            responseValue = ByteBuffer.wrap(readBuffer).toString();
            // 检查响应值是否符合预期
            if (responseValue != "0") { // 假设0表示未响应或无效值
                responseReceived = true;
                System.out.println("PLC响应值: " + responseValue);
            } else {
                // 等待一段时间后再检查
                TimeUnit.MILLISECONDS.sleep(pollingMillseconds); // 100毫秒的轮询间隔
            }
        }
        return responseValue;
    }

}
